package com.asiainfo.dacp.datastash.broker.facade.service;

import com.asiainfo.dacp.datastash.broker.core.BrokerModel;
import com.asiainfo.dacp.datastash.broker.core.StashUnitProcessModel;
import com.asiainfo.dacp.datastash.broker.core.vo.Broker;
import com.asiainfo.dacp.datastash.broker.core.vo.StashUnitTask;
import com.asiainfo.dacp.datastash.broker.core.vo.StashUnitProcess;
import com.asiainfo.dacp.datastash.broker.tracelog.StashTraceLogVo;
import com.asiainfo.dacp.datastash.broker.tracelog.StashTraceLogger;
import com.asiainfo.dacp.resource.service.ResourceRedisService;
import com.asiainfo.dacp.resource.vo.BrokerResource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 *
 * 线性规划帮助类
 *
 * @author MeiKefu
 * @date 2017-10-31
 */
@Service
public class LinearProgramming {

    @Autowired
    private StashTraceLogger tracelog;
    @Autowired
    private ResourceRedisService resourceRedisService;
    @Autowired
    private BrokerModel brokerModel;
    @Autowired
    private StashUnitProcessModel stashUnitProcessModel;
    
    private String clzName = this.getClass().getSimpleName();

    /**
     * 线性规划，返回计算好的任务分片
     */
    public Broker programming(StashUnitTask stashUnitTask, List<Broker> brokers){
        tracelog.info(StashTraceLogVo.buildStashTraceLogVo(stashUnitTask,clzName,"linerProg:start","开始线性规划执行Broker"));

        Broker broker = null;

        if(brokers!=null && brokers.size()>0){
        	List<BrokerResource> brokerResourceList = sortByResourceIo(brokers);
        	BrokerResource brokerResource = seletorBroker(stashUnitTask, brokerResourceList);
        	if(brokerResource==null){
        		broker = brokers.get(0);
        		tracelog.info(StashTraceLogVo.buildStashTraceLogVo(stashUnitTask,clzName,"linerProg:complete","未获取资源信息，执行默认主机为："+broker));
        		return broker;
        	}else{
        		for(Broker aBroker : brokers){
                	if(brokerResource.getBrokerId().equals(aBroker.getBrokerId())&&brokerResource.getBrokerIp().equals(aBroker.getBrokerIp())){
                        broker = aBroker;
                        tracelog.info(StashTraceLogVo.buildStashTraceLogVo(stashUnitTask,clzName,"linerProg:complete","完成规划，执行主机为："+broker));
                        break;
                	}
                }
        	}
            
        }else{
            tracelog.info(StashTraceLogVo.buildStashTraceLogVo(stashUnitTask,clzName,"linerProg:error","可用broker为空"));
        }
        return broker;
    }
    /**
     * 按照网路IO和磁盘IO和升序
     * @param brokers
     * @return
     */
    private List<BrokerResource> sortByResourceIo(List<Broker> brokers){
    	List<BrokerResource> brokerResourceList = resourceRedisService.getBrokerResourceList();
    	List<BrokerResource> usableResourceList = new ArrayList<BrokerResource>();
    	for (Broker broker : brokers) {
			for (BrokerResource brokerResource : brokerResourceList) {
				if(broker.getBrokerId().equals(brokerResource.getBrokerId())&&broker.getBrokerIp().equals(brokerResource.getBrokerIp())){
					usableResourceList.add(brokerResource);
					break;
				}
			}
		}
    	Collections.sort(usableResourceList, new Comparator<BrokerResource>(){
			@Override
			public int compare(BrokerResource o1, BrokerResource o2) {
				Long o1sum=o1.getNetRecv()+o1.getNetSent()+o1.getIoRead()+o1.getIowrite();
				Long o2sum=o2.getNetRecv()+o2.getNetSent()+o2.getIoRead()+o2.getIowrite();
				return o1sum.compareTo(o2sum);
			}
    	});
    	return usableResourceList;
    }
    /**
     * 判断最优的broker中是否包含该接口单元下任务，优先考虑平均分配
     * @param stashUnitTask
     * @param brokerResourceList
     * @return
     */
    private BrokerResource seletorBroker(StashUnitTask stashUnitTask,List<BrokerResource> brokerResourceList){
    	
    	Map<String,String> brokerTaskMap = brokerModel.getBrokerUnitTaskList();
    	StashUnitProcess stashUnitProcess = stashUnitProcessModel.getUnitProcessList(stashUnitTask.getUnitProcId());
    	List<StashUnitTask> processUnitStaskList = stashUnitProcess.getTasks();
    	List<String> taskProcIds = new ArrayList<String>();
    	for (StashUnitTask processStashUnitTask : processUnitStaskList) {
			if(!processStashUnitTask.getTaskProcId().equals(stashUnitTask.getTaskProcId())){
				taskProcIds.add(processStashUnitTask.getTaskProcId());
			}
		}
    	BrokerResource result = null;
    	for (BrokerResource brokerResource : brokerResourceList) {
			String brokerId = brokerResource.getBrokerId();
			Iterator<Map.Entry<String, String>> it = brokerTaskMap.entrySet().iterator();
			boolean isExistTask=false;//判断是否存在相同
			while (it.hasNext()) {
				Map.Entry<String,String> entry = (Map.Entry<String,String>) it
						.next();
				if(entry.getValue().equals(brokerId)&&taskProcIds.contains(entry.getKey())){
					isExistTask=true;
					break;
				}
			}
			if(!isExistTask){
				result=brokerResource;
				break;
			}
		}
    	
    	if(result==null&&brokerResourceList.size()>0){
    		result=brokerResourceList.get(0);
    	}
    	
    	return result;
    }
    
}
